package com.yugao.fintech.antelope.auth.oauth2.support;

import com.yugao.fintech.antelope.auth.model.LockUser;
import com.yugao.fintech.antelope.auth.model.bo.CheckLoginUser;
import com.yugao.fintech.antelope.auth.model.entity.LocalUser;
import com.yugao.fintech.antelope.auth.model.rqrs.LocalUserGetReq;
import com.yugao.fintech.antelope.auth.oauth2.Authentication;
import com.yugao.fintech.antelope.auth.oauth2.model.RegisteredClient;
import com.yugao.fintech.antelope.auth.service.LoginUserService;
import com.yugao.fintech.antelope.auth.utils.OAuth2Utils;
import com.yugao.fintech.antelope.base.model.constants.SecurityCons;
import com.yugao.fintech.antelope.base.model.enums.AuthErrorEnum;
import com.yugao.fintech.antelope.base.model.module.auth.GrantTypeEnum;
import com.yugao.fintech.antelope.base.model.module.auth.LoginUser;
import com.yugao.fintech.framework.assistant.utils.DateUtils;
import com.yugao.fintech.framework.assistant.utils.exception.BizException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Component
@RequiredArgsConstructor
public class Oauth2GrantSms extends BaseOauth2Grant {
    private final LoginUserService loginUserService;

    @Override
    protected LoginUser authenticate(Authentication authentication) {

        Map<String, Object> parameters = authentication.getAdditionalParameters();
        String account = (String) parameters.get(SecurityCons.SmsParam.PHONE);

        // 查询用户
        LocalUser localUser = authApi.getUser(LocalUserGetReq.builder().account(account).build());
        if (Objects.isNull(localUser)) {
            throw new BizException(AuthErrorEnum.USER_ACCOUNT_NOT_EXIST);
        }

        LoginUser loginUser = super.buildAuthUser(account, localUser);

        // 校验是否被锁定
        LockUser lockUser = loginUserService.getLockUser(account, authentication);
        if (Objects.nonNull(lockUser)) {
            String unlockTime = DateUtils.distance(System.currentTimeMillis(), lockUser.getUnLockTimestamp(), true);
            throw new BizException(AuthErrorEnum.LOGIN_LOCKED, unlockTime);
        }

        // 开始校验用户
        CheckLoginUser.of(account, "none", loginUser)
                .isDeleted().isDisabled().throwError(BizException::new);
        return loginUser;
    }

    @Override
    protected GrantTypeEnum grantType() {
        return GrantTypeEnum.APP;
    }

    @Override
    protected void checkClient(RegisteredClient registeredClient) {
        Assert.notNull(registeredClient, "registeredClient is null");
        if (!registeredClient.getAuthorizationGrantTypes().contains(GrantTypeEnum.APP.getCode())) {
            throw new BizException(AuthErrorEnum.OAUTH2_UNAUTHORIZED_CLIENT);
        }
    }

    @Override
    protected boolean isCheckCaptcha() {
        return true;
    }

    /**
     * 校验扩展参数 密码模式密码必须不为空
     *
     * @param request 参数列表
     */
    @Override
    public void checkParams(HttpServletRequest request) {
        super.checkParams(request);
        MultiValueMap<String, String> parameters = OAuth2Utils.getParameters(request);
        // PHONE (REQUIRED)
        String phone = parameters.getFirst(SecurityCons.SmsParam.PHONE);
        if (!StringUtils.hasText(phone) || parameters.get(SecurityCons.SmsParam.PHONE).size() != 1) {
            throw new BizException("请输入手机号");
        }
    }
}
